package cc.rengu.igas.opms.core.service.trans.common;

import cc.rengu.igas.opms.common.enums.RespCodeEnum;
import cc.rengu.igas.opms.common.util.QrCodeUtil;
import cc.rengu.igas.opms.core.service.base.ManageService;
import cc.rengu.igas.opms.facade.base.Header;
import cc.rengu.igas.opms.facade.request.GetUserAuthCodeRequest;
import cc.rengu.igas.opms.facade.response.GetUserAuthCodeResponse;
import cc.rengu.igas.share.common.constant.ShareParamConstant;
import cc.rengu.igas.share.common.constant.TransCacheConstant;
import cc.rengu.igas.share.core.model.MchntInfo;
import cc.rengu.igas.share.core.model.QrCodeInfo;
import cc.rengu.igas.share.core.realize.BompService;
import cc.rengu.igas.share.core.realize.MchntService;
import cc.rengu.igas.share.core.realize.impl.BompServiceImpl;
import cc.rengu.igas.share.core.realize.impl.MchntServiceImpl;
import cc.rengu.oltp.service.base.ChannelBaseService;
import cc.rengu.oltp.service.common.constant.AppParamConstant;
import cc.rengu.oltp.service.common.constant.TreeNodeConstant;
import cc.rengu.oltp.service.common.dao.MchntOrderInfoMapper;
import cc.rengu.oltp.service.common.dao.UserOrderInfoMapper;
import cc.rengu.oltp.service.common.dao.impl.MchntOrderInfoMapperImpl;
import cc.rengu.oltp.service.common.dao.impl.UserOrderInfoMapperImpl;
import cc.rengu.oltp.service.common.entity.ChannelCallCfg;
import cc.rengu.oltp.service.common.entity.MchntOrderInfo;
import cc.rengu.oltp.service.common.entity.UserOrderInfo;
import cc.rengu.oltp.service.common.enums.CheckResultEnum;
import cc.rengu.oltp.service.common.enums.TransStatusEnum;
import cc.rengu.oltp.service.model.BizException;
import cc.rengu.oltp.service.model.BizResponse;
import cc.rengu.oltp.service.model.OrderInfo;
import cc.rengu.oltp.service.realize.TransCustomImpl;
import cc.rengu.oltp.utility.util.ConvertUtil;
import cc.rengu.oltp.utility.util.GlobalTransUtil;
import cc.rengu.oltp.utility.util.StringUtil;
import cc.rengu.oltp.utility.util.XmlTreeUtil;

import java.net.URLDecoder;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 获取微信授权码.
 * modify by wangcheng 2021-09-13
 */
public class GetUserAuthCodeService extends ManageService implements TransCustomImpl {

    @Override
    protected Object bizBeforeCust() throws Exception {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        GetUserAuthCodeRequest request = new GetUserAuthCodeRequest();
        // 读取存在xml树里的实体类
        ConvertUtil.convertOutput(request);
        xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.FRONT_SEQ_NUM, request.getHeader().getTraceNo());
        return request;
    }

    @Override
    protected BizResponse bizProcessCust(Object request) throws Exception {
        GetUserAuthCodeRequest getUserAuthCodeRequest = (GetUserAuthCodeRequest) request;
        Header header = getUserAuthCodeRequest.getHeader();
        String authChannel = getUserAuthCodeRequest.getAuthChannel();
        String qrUrl = getUserAuthCodeRequest.getQrUrl();

        if (!StringUtil.isEmptyOrNull(qrUrl)) {
            boolean checkResult = mchntValidCheck(header.getInstId(), authChannel, qrUrl);
            if (!checkResult) {
                rglog.error("商户不存在或者商户状态异常或者商户未进行微信支付宝进件!");
                throw new BizException(RespCodeEnum.MCHNT_INVALID.getRespCode(), RespCodeEnum.MCHNT_INVALID.getRespDesc());
            }
        }

        //调用通道接口
        if (null == txnInfo.getChannelCallCfgList() || txnInfo.getChannelCallCfgList().isEmpty()) {
            rglog.error("<{}-{}>交易未配置交易通道服务调用配置信息！", txnInfo.getSrcTxnAuthCfg().getTxnNum(), txnInfo.getSrcTxnAuthCfg().getTxnName());
            throw new BizException(RespCodeEnum.CHANNEL_CONFIG_NOT_EXIST.getRespCode(), RespCodeEnum.CHANNEL_CONFIG_NOT_EXIST.getRespDesc());
        }
        List<ChannelCallCfg> channelCallCfgList = txnInfo.getChannelCallCfgList().stream().filter(item ->
                item.getCallIndex().equals(ChannelBaseService.FIRST_CHANNEL_CALL_INDEX)).collect(Collectors.toList());
        ChannelCallCfg channelCallCfg = channelCallSceneDiscern(getUserAuthCodeRequest, channelCallCfgList);
        Class channelClasz = Class.forName(channelCallCfg.getCallChannelImpl());
        ChannelBaseService channelBaseService = (ChannelBaseService) channelClasz.newInstance();
        channelBaseService.callService(txnInfo, null, channelCallCfg.getBizScene(), request);

        //组装应答信息
        GetUserAuthCodeResponse getUserAuthCodeResponse = new GetUserAuthCodeResponse();
        getUserAuthCodeResponse.setHeader(getUserAuthCodeRequest.getHeader());
        getUserAuthCodeResponse.setRespCode(RespCodeEnum.TRANS_SUCCESS.getRespCode());
        getUserAuthCodeResponse.setRespDesc(RespCodeEnum.TRANS_SUCCESS.getRespDesc());
        getUserAuthCodeResponse.setAuthUrl((String) GlobalTransUtil.getCacheValue(TransCacheConstant.WXAL_AUTH_URL));
        BizResponse<GetUserAuthCodeResponse> bizResponse = new BizResponse<>();
        bizResponse.setRspSysId(AppParamConstant.SYS_ID);
        bizResponse.setRespCode(RespCodeEnum.TRANS_SUCCESS.getRespCode());
        bizResponse.setRespDesc(RespCodeEnum.TRANS_SUCCESS.getRespDesc());
        bizResponse.setResult(getUserAuthCodeResponse);
        return bizResponse;
    }

    @Override
    protected void bizAfterCust(Object response) throws Exception {
        BizResponse bizResponse = (BizResponse) response;
        GetUserAuthCodeResponse getUserAuthCodeResponse = (GetUserAuthCodeResponse) bizResponse.getResult();
        ConvertUtil.convertInput(getUserAuthCodeResponse);
    }

    /**
     * 商户有效性检查
     *
     * @param instId      多法人标识
     * @param authChannel 授权渠道
     * @param qrUrl       二维码
     * @return true-检查通过,false-检查失败
     * @throws Exception 异常
     */
    private boolean mchntValidCheck(String instId, String authChannel, String qrUrl) throws Exception {
        //获取交易的商户号
        String mchntNo;
        //去掉C1码中的tt和si参数
        qrUrl = QrCodeUtil.filterTtAndSi(qrUrl);
        /*判断是否银标码：收银台域名?qrCode=https//95516.com/xxxx*/
        if (qrUrl.contains("qr.95516.com")) {
            int qrIndex = qrUrl.indexOf("qrCode=");
            if (qrIndex < 0) {
                rglog.error("无效二维码<{}>", qrUrl);
                throw new BizException(RespCodeEnum.GET_QRCODE_INVALID.getRespCode(), RespCodeEnum.GET_QRCODE_INVALID.getRespDesc());
            }
            qrUrl = qrUrl.substring(qrIndex + 7);
            /*银联回调时url编码了,此时urldecode*/
            qrUrl = URLDecoder.decode(qrUrl, "UTF-8");
        }
        rglog.info("实际二维码url<{}>", qrUrl);
        //判断二维码类型
        int lastIndex = qrUrl.lastIndexOf("inf=");
        if (lastIndex < 0) {
            rglog.error("二维码<{}>格式错误", qrUrl);
            throw new BizException(RespCodeEnum.GET_QRCODE_INVALID.getRespCode(), RespCodeEnum.GET_QRCODE_INVALID.getRespDesc());
        }
        String qrCodeType = qrUrl.substring(lastIndex + 4, lastIndex + 5);

        if ("D".equals(qrCodeType)) {
            rglog.debug("动态二维码交易，根据用户订单表获取交易商户号");
            UserOrderInfoMapper userOrderInfoMapper = new UserOrderInfoMapperImpl();
            UserOrderInfo userOrderInfo = userOrderInfoMapper.selectUserOrderInfoByOrderUrl(instId, qrUrl);
            if (userOrderInfo == null) {
                rglog.error("用户订单表中不存在该动态二维码交易记录,instId:<{}>,orderUrl:<{}>", instId, qrUrl);
                throw new BizException(RespCodeEnum.ORDER_NOEXIT.getRespCode(), RespCodeEnum.ORDER_NOEXIT.getRespDesc());
            }
            //获取商户订单
            MchntOrderInfoMapper mchntOrderInfoMapper = new MchntOrderInfoMapperImpl();
            List<MchntOrderInfo> mchntOrderInfos = mchntOrderInfoMapper.selectMchntOrderInfoBySysSeqNum(userOrderInfo.getInstId(), userOrderInfo.getSysSeqNum());
            if (null == mchntOrderInfos || mchntOrderInfos.isEmpty()) {
                rglog.info("商户订单不存在,instId:<{}>,sysSeqNum:<{}>", userOrderInfo.getInstId(), userOrderInfo.getSysSeqNum());
                throw new BizException(RespCodeEnum.ORDER_NOEXIT.getRespCode(), RespCodeEnum.ORDER_NOEXIT.getRespDesc());
            }
            //合并订单支付的时候商户号取平台商户号
            if (mchntOrderInfos.size() == 1) {
                rglog.info("单笔订单支付，商户号取商户订单表中的商户号.mchntNo:<{}>", mchntOrderInfos.get(0).getMchntNo());
                mchntNo = mchntOrderInfos.get(0).getMchntNo();
            } else {
                if ("ALIPAY".equalsIgnoreCase(authChannel)) {
                    rglog.info("支付宝支付不支持合并订单支付");
                    throw new BizException(RespCodeEnum.NOTSUPPORT_MERGEPAY.getRespCode(), RespCodeEnum.NOTSUPPORT_MERGEPAY.getRespDesc());
                }
                rglog.info("合并订单支付商户号取平台商户号，platMchntNo:<{}>", userOrderInfo.getGroupMchntNo());
                mchntNo = userOrderInfo.getGroupMchntNo();
            }
        } else if ("S".equals(qrCodeType)) {
            rglog.debug("静态码交易，根据二维码明细表判断二维码是否存在并获取商户号");
            //校验二维码信息
            BompService bompService = new BompServiceImpl();
            QrCodeInfo qrCodeInfo = bompService.getQrCodeInfo(instId, qrUrl, null);
            if (null == qrCodeInfo) {
                rglog.error("二维码信息不存在，交易阻断");
                throw new BizException(RespCodeEnum.GET_QRCODE_INVALID.getRespCode(), RespCodeEnum.GET_QRCODE_INVALID.getRespDesc());
            }
            mchntNo = qrCodeInfo.getMchntNo();
        } else {
            rglog.error("二维码<{}>格式错误", qrUrl);
            throw new BizException(RespCodeEnum.GET_QRCODE_INVALID.getRespCode(), RespCodeEnum.GET_QRCODE_INVALID.getRespDesc());
        }
        /* 获取商户信息 */
        MchntService mchntService = new MchntServiceImpl();
        MchntInfo mchntInfo = mchntService.getMchntInfo(instId, mchntNo);
        return null != mchntInfo && (!StringUtil.isEmptyOrNull(mchntInfo.getWechatMchntNo()) || !StringUtil.isEmptyOrNull(mchntInfo.getAlipayMchntNo()));
    }

    @Override
    public ChannelCallCfg channelCallSceneDiscern(Object request, List<ChannelCallCfg> channelCallCfgList) throws Exception {
        GetUserAuthCodeRequest getUserAuthCodeRequest = (GetUserAuthCodeRequest) request;
        String authChannel = getUserAuthCodeRequest.getAuthChannel();
        String finalBizScene = "ALIPAY".equalsIgnoreCase(authChannel) ? "01" : ShareParamConstant.CALL_CFG_DEFAULT_BIZ_SCENE;
        Optional<ChannelCallCfg> channelCallCfgOpt = channelCallCfgList.stream().filter(item ->
                item.getBizScene().equals(finalBizScene)).findFirst();
        return channelCallCfgOpt.orElse(null);
    }

    @Override
    public CheckResultEnum channelCallPreCheck(Object request, ChannelCallCfg channelCallCfg, OrderInfo orderInfo) throws Exception {
        return CheckResultEnum.PASSED;
    }

    @Override
    public TransStatusEnum channelCallResultProc(Object request, ChannelCallCfg channelCallCfg, TransStatusEnum transStatusEnum, Object channelResponse, OrderInfo needUpdateOrderInfo) throws Exception {
        return transStatusEnum;
    }
}
